package com.intretech.umsin.common.utils;

import org.apache.commons.lang3.reflect.FieldUtils;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 数据转换工具类
 *
 * @author 李启联
 *
 */
public class ConvertUtils {


    /**
     * 把Map对象中的内容填充到指定实体对象中，<em>支持递归<em/>
     * 填充规则：[实体属性名称与源Map对象字段 	  1.不分大小写  2.驼峰格式相互可以转成 相对应],找到便填充。
     * @param map 源Map对象数据
     * @param type 目标实体对象的类型（如：T.class）
     * @return 填充好的实体对象
     * @throws Exception
     */
    public static <T> T dataMapToObject(Map<String, Object> map, Class<T> type)  {
        if (null == map || map.isEmpty())
            return null;
        T entity = null;
        try {
            entity = (T) Class.forName(type.getName()).newInstance();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String fieldName = "";
        Object obj =null,val=null;
        Class elementType = null;
        Field[] fields = FieldUtils.getAllFields(type);
        for (Field field : fields) { // 遍历所有属性
            fieldName = field.getName(); // 获取属性的名字

            field.setAccessible(true);

            if(ReflectionUtils.isStaticFinalField(field))//如果该字段使用了static final 修饰 【通常这么修饰的字段是用来定义常量的】
                continue;//	遍历下一个

            obj = CUtils.getValueFromMapByLikeKey(fieldName, map);//平行查找与属性名相同键的Map对应的值

            if (field.getType().isAssignableFrom(List.class)) { // 如果属性是另外类型实体的泛型List集合
                if (null != obj) {
                    if (obj instanceof List || obj.getClass().isAssignableFrom(List.class)){
                        List collection = new ArrayList();
                        elementType = ReflectionUtils.getFieldClass(field);// 得到List泛型参数类型
                        for(Map<String, Object> subMap : (List<Map<String, Object>>)obj) {
                            collection.add(dataMapToObject(subMap,elementType));
                        }
                        try {
                            field.set(entity,collection);
                        } catch (IllegalAccessException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            }
            else if(null != obj && (obj.getClass().isAssignableFrom(Map.class) || obj.getClass().isAssignableFrom(LinkedHashMap.class))){//如果属性是另外类型的单个实体
                try {
                    field.set(entity,dataMapToObject((Map<String, Object>)obj,field.getType()));
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
            else if(null != obj && obj.getClass().isAssignableFrom(ArrayList.class)){//如果属性是另外类型的单个实体
                try {
                    field.set(entity,dataMapListToObjects((List<Map<String, Object>>)obj,field.getType()));
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
            else {// 如果属性类型是 'string','Date','int', 'long','Double'......
                if (null != obj && obj.toString().trim().length() > 0) {
                    val = convertObjectToTargetType(obj, field.getType());
                    try {
                        field.set(entity, val);
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }

        }

        return entity;
    }

    /**
     * 把List<Map>对象中的内容填充到指定实体对象集合中，<em>支持递归<em/>
     * @param mapList 源List<Map>对象数据
     * @param type 目标实体对象的类型（如：T.class）
     * @return 填充好的实体对象集合
     * @throws Exception
     */
    public static <T> List<T> dataMapListToObjects(List<Map<String, Object>> mapList, Class<T> type)  {
        List collection = new ArrayList();
        for(Map<String, Object> map : mapList) {
            collection.add(dataMapToObject(map,type));
        }
        return collection;
    }

    /**
     * 将指定的对象转换为对应类型的对象
     *
     * @param object
     *            要转换的对象
     * @param type
     *            对应类型 如：Integer.class Date.class 等
     * @return
     */
    public static Object convertObjectToTargetType(Object object, Class<?> type) {
        if (type == String.class) {
            return object.toString();
        } else if (type == int.class || type == Integer.class) {
            if (object instanceof Number) {
                Number number = (Number) object;
                return number.intValue();
            } else{
                if (object instanceof Boolean) {
                    return ((Boolean)object) ? 1 : 0 ;
                }
                return Integer.parseInt(object.toString());
            }
        } else if (type == byte.class || type == Byte.class) {
            if (object instanceof Number) {
                Number number = (Number) object;
                return number.byteValue();
            } else
                return Byte.parseByte(object.toString());
        } else if (type == short.class || type == Short.class) {
            if (object instanceof Number) {
                Number number = (Number) object;
                return number.shortValue();
            } else
                return Short.parseShort(object.toString());
        } else if (type == long.class || type == Long.class) {
            if (object instanceof Number) {
                Number number = (Number) object;
                return number.longValue();
            } else
                return Long.parseLong(object.toString());
        } else if (type == float.class || type == Float.class) {
            if (object instanceof Number) {
                Number number = (Number) object;
                return number.floatValue();
            } else
                return Float.parseFloat(object.toString());
        } else if (type == double.class || type == Double.class) {
            if (object instanceof Number) {
                Number number = (Number) object;
                return number.doubleValue();
            } else
                return Double.parseDouble(object.toString());
        } else if (type == boolean.class || type == Boolean.class) {
            return Boolean.valueOf(object.toString());
        } else if (type == Date.class) {
            if(object instanceof Date){
                return (Date)object;
            }else {
                return DateUtils.parse(object.toString().replace("/", "-"), (object.toString().length() > 10 ? DateUtils.FORMAT_LONG : DateUtils.FORMAT_SHORT));
            }
        }else if(type == LocalDate.class){
            if(object instanceof Date){
                return DateUtils.asLocalDate((Date) object);
            }else {
                if(object.toString().length() == 8){
                    return LocalDate.parse(object.toString(), DateTimeFormatter.BASIC_ISO_DATE);
                }
                return DateUtils.asLocalDate(DateUtils.parse(object.toString().replace("/", "-"), (object.toString().length() > 10 ? DateUtils.FORMAT_LONG : DateUtils.FORMAT_SHORT)));
            }
        }else if(type == LocalDateTime.class){
            if(object instanceof Date){
                return DateUtils.asLocalDateTime((Date) object);
            }else {
                //支持 20210301 这格式
                if(object.toString().length() == 8 && !object.toString().contains("-") && !object.toString().contains("/")){
                    return DateUtils.asLocalDateTime(DateUtils.asDate(LocalDate.parse(object.toString(), DateTimeFormatter.BASIC_ISO_DATE)));
                }
                if(object.toString().contains("T")){
                   return DateUtils.asLocalDateTime(DateUtils.parse(object.toString().replace("T", " "), (object.toString().length() > 10 ? DateUtils.FORMAT_LONG : DateUtils.FORMAT_SHORT)));
                }
                return DateUtils.asLocalDateTime(DateUtils.parse(object.toString().replace("/", "-"), (object.toString().length() > 10 ? DateUtils.FORMAT_LONG : DateUtils.FORMAT_SHORT)));
            }
        }
        else if(type == BigDecimal.class ) {
            try {
                return new BigDecimal(object.toString());
            }catch (Exception e){
                return new BigDecimal(0);
            }
        }
        else if(type == Timestamp.class){
            if (object instanceof Number) {
                Number number = (Number) object;
                return new Timestamp((number.longValue()));
            } else{
                return new Timestamp(DateUtils.parse(object.toString(), DateUtils.FORMAT_LONG).getTime());
            }
        }

        return object;

    }


    public static <T> List<T> castList(Object obj, Class<T> clazz) {
        List<T> result = new ArrayList<T>();
        if(obj instanceof List<?>) {
            for (Object o : (List<?>) obj) {
                result.add(clazz.cast(o));
            }
            return result;
        }
        return null;
    }
}
